package net.kqinfo.core.shiro;

import java.io.Serializable;

import net.kqinfo.common.util.scrypt.BCrypt;
import net.kqinfo.core.Constants;
import net.kqinfo.core.controller.IndexController;
import net.kqinfo.core.model.User;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAccount;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jfinal.core.ActionInvocation;
import com.jfinal.ext.render.CaptchaRender;

public class ShiroDbRealm extends AuthorizingRealm {

	private static final Logger log = LoggerFactory
			.getLogger(ShiroDbRealm.class);

	// 是否启用超级管理员
	protected boolean activeRoot = false;

	// 是否使用验证码
	protected boolean useCaptcha = false;

	private IndexController indexController;

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principals) {
		System.out.println("进入查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用");
		return null;
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken authcToken) throws AuthenticationException {
		CaptchaUsernamePasswordToken token = (CaptchaUsernamePasswordToken) authcToken;
		if (useCaptcha) {
			try {
				if (CaptchaRender.validate(indexController, token.getCaptcha()
						.toUpperCase(), Constants.RANDOM_CODE_KEY)) {
					throw new IncorrectCaptchaException("验证码错误！");
				}
			} catch (Exception e) {
				// session如果没有刷新，validateResponseForID会抛出com.octo.captcha.service.CaptchaServiceException的异常
				throw new IncorrectCaptchaException("验证码错误！");
			}
		}

		User user = User.dao.findFirst("select * from security_user where username = ? ",
				token.getUsername());
		if (user != null) {
			if (user.get("status").equals("disabled")) {
				throw new DisabledAccountException();
			}
			if (!BCrypt.checkpw(String.valueOf(token.getPassword()),user.getStr("password"))) {
				throw new IncorrectCredentialsException();
			}
			ShiroUser shiroUser = new ShiroUser(user.getLong("id"),
					user.getStr("username"), user);
			return new SimpleAccount(shiroUser,token.getPassword(),getName());
		} else {
			throw new UnknownAccountException();
		}
	}

	public static class ShiroUser implements Serializable {

		private static final long serialVersionUID = -1748602382963711884L;
		private Long id;
		private String loginName;
		private User user;

		public ShiroUser() {

		}

		/**
		 * 构造函数
		 * 
		 * @param id
		 * @param loginName
		 * @param email
		 * @param createTime
		 * @param status
		 */
		public ShiroUser(Long id, String loginName, User user) {
			this.id = id;
			this.loginName = loginName;
			this.user = user;
		}

		/**
		 * 返回 id 的值
		 * 
		 * @return id
		 */
		public Long getId() {
			return id;
		}

		/**
		 * 返回 loginName 的值
		 * 
		 * @return loginName
		 */
		public String getLoginName() {
			return loginName;
		}

		/**
		 * 返回 user 的值
		 * 
		 * @return user
		 */
		public User getUser() {
			return user;
		}

		/**
		 * 本函数输出将作为默认的<shiro:principal/>输出.
		 */
		@Override
		public String toString() {
			return loginName;
		}
	}

	public IndexController getIndexController(ActionInvocation ai) {
		return indexController = (IndexController)ai.getController();
	}

	public void setIndexController(IndexController indexController) {
		this.indexController = indexController;
	}

	public boolean isActiveRoot() {
		return activeRoot;
	}

	public void setActiveRoot(boolean activeRoot) {
		this.activeRoot = activeRoot;
	}

	public boolean isUseCaptcha() {
		return useCaptcha;
	}

	public void setUseCaptcha(boolean useCaptcha) {
		this.useCaptcha = useCaptcha;
	}

}
